package org.hackystat.sdsa.analyzer.model.activity.edit;

import java.util.Map;
import java.util.logging.Logger;

import jess.Fact;
import jess.JessException;
import jess.RU;
import jess.Rete;
import jess.Value;

import org.hackystat.sdsa.analyzer.control.SensorDataUtil;
import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorData;

/**
 * Implements production code edit action. Production is the actual code
 * which is not test.
 * 
 * @author Hongbing Kou
 */
public class ProductionEditActivity extends EditActivity {
  /** Class name. */
  private String className;
  /** Number of methods. */
  private int numOfMethods = 0;
  /** Number of statements. */
  private int numOfStatements = 0;
  /** Number of method change. */
  private int methodIncrease = 0;
  /** Number of statement change. */
  private int statementIncrease = 0;
  
  /** Class name. */
  public static final String CLASS_NAME = "class-name";
  /** Current statements */
  public static final String CURRENT_STATEMENTS = "current-statements";
  /** Current number of methods. */
  public static final String CURRENT_METHODS = "current-methods";
  private static final String PRODUCT_EDIT_TYPE = "PRODUCTION EDIT";

  /**
   * Empty production edit activity.
   */
  public ProductionEditActivity() {
    super();
    super.setType(PRODUCT_EDIT_TYPE);
  }
  
  /**
   * Constructs a production edit action instance.
   * 
   * @param sensorData Sensor data.
   * @param logger Logger.
   */
  public ProductionEditActivity(SensorData sensorData, Logger logger) {
    super(sensorData, logger);
    super.setType(PRODUCT_EDIT_TYPE);
    
    Map<String, String> propMap = SensorDataUtil.propMap(sensorData);
    this.className = propMap.get(CLASS_NAME);
  
    String numOfMethods = propMap.get(ProductionEditActivity.CURRENT_METHODS);
    this.numOfMethods = Integer.parseInt(numOfMethods);

    String numOfStatements = propMap.get(ProductionEditActivity.CURRENT_STATEMENTS);
    this.numOfStatements = Integer.parseInt(numOfStatements);
  }

  /**
   * Makes Jess facts in the given Jess rete engine.
   * 
   * @param index Action index in episode. 
   * @param engine Jess rete engine.
   * @throws JessException If error while constructing jess action.
   * @return The asserted fact.
   */
  @Override public Fact assertActivity(int index, Rete engine) throws JessException  {
    Fact assertedFact = null;
    if (isSubstantial()) {
      Fact f = new Fact("ProductionEditActivity", engine);
      f.setSlotValue(INDEX_SLOT, new Value(index, RU.INTEGER));
      String file = super.extractFileName(super.getResourceUri());
      f.setSlotValue(FILE_SLOT, new Value(file, RU.STRING));
      f.setSlotValue("duration", new Value(this.getDuration(), RU.INTEGER));
      f.setSlotValue("methodChange", new Value(this.getMethodIncrease(), RU.INTEGER));
      f.setSlotValue("statementChange", new Value(this.getStatementIncrease(), RU.INTEGER));
      f.setSlotValue("byteChange", new Value(this.getFileSizeIncrease(), RU.INTEGER));
      
      assertedFact = engine.assertFact(f);
    }
    
    return assertedFact;
  }
  
  
  /**
   * Sets number of statement change.
   * 
   * @param value Number of statement. 
   */
  public void setStatementIncrease(int value) {
    this.statementIncrease = value;
  }
  /**
   * Gets number of statement change.
   * 
   * @return Number of statement change. 
   */
  public int getStatementIncrease() {
    return this.statementIncrease;
  }

  /**
   * Sets the number of method change.
   * 
   * @param value Number of method change.
   */
  public void setMethodIncrease(int value) {
    this.methodIncrease = value;
  }
  
  /**
   * Gets number of method change.
   * 
   * @return Number of method change.
   */
  public int getMethodIncrease() {
    return this.methodIncrease;
  }

  /**
   * Sets number of method in this file.
   * 
   * @param value Number of method.
   */
  public void setNumOfMethods(int value) {
    this.numOfMethods = value;    
  }
  
  /**
   * Gets number of methods. 
   * 
   * @return Number of methods.
   */
  public int getNumOfMethods() {
    return this.numOfMethods;
  }
  

  /**
   * Sets number of statements.
   * 
   * @param numOfStatements Number of statements.
   */
  public void setNumOfStatements(int numOfStatements) {
    this.numOfStatements = numOfStatements;
  }

  /**
   * Gets number of statements.
   * 
   * @return Number of statements.
   */
  public int getNumOfStatements() {
    return this.numOfStatements;
  }
  
  /**
   * Gets production code edit string.
   * 
   * @return Production code edit string. 
   */
  @Override public String toString() {
    StringBuffer buf = new StringBuffer();
    buf.append(super.toString());
    buf.append(" PRODUCTION {");
    
    buf.append(makeMetricPair("MI", this.methodIncrease, this.numOfMethods));    
    buf.append(makeMetricPair(", SI", this.statementIncrease, this.numOfStatements));
    buf.append(makeMetricPair(", FI", this.fileSizeIncrease, this.fileSize));
    
    buf.append('}');
    
    return  buf.toString();
  }  

  /**
   * Checks production code edit.
   * 
   * @return True if edit time is positive.
   */
  @Override public boolean hasProgress() {
    return this.getDuration() > 0 || this.getFileSizeIncrease() != 0;
  }  
  

  /**
   * Checks whether this edit work is significant or not.
   * 
   * @return True if the edit is substantial and false otherwise.
   */
  @Override public boolean isSubstantial() {
//      return this.getDuration() > 0 && 
//        (this.getFileSizeIncrease() != 0 || this.methodIncrease != 0 || 
//         this.statementIncrease != 0);  
    return this.getFileSizeIncrease() != 0 || this.methodIncrease != 0 || 
           this.statementIncrease != 0;  
  }
    
  /** 
   * Get the representation of this activity. 
   * 
   * @return String representation of this activity.
   */
  @Override public String getRepresentation() {
    StringBuffer buf = new StringBuffer();
    buf.append(super.getDuration()).append("sec ");
    
    buf.append(makeMetricPair("MI", this.methodIncrease, this.numOfMethods)).append(", ");    
    buf.append(makeMetricPair("SI", this.statementIncrease, this.numOfStatements)).append(", ");
    buf.append(makeMetricPair("FI", this.fileSizeIncrease, this.fileSize));

    return buf.toString();
  }

  
  /***
   * Sets class name.
   * 
   * @param className Class name.
   */
  public void setClassName(String className) {
    this.className = className;
  }

  /***
   * Gets class name.
   * 
   * @return Class name.
   */
  public String getClassName() {
    return this.className;
  }
}